iT邦幫忙

2022 iThome 鐵人賽

DAY 9
2

Events

服務內建一個事件匯流器來支援事件驅動架構,以及發送事件至本地與遠端服務。

注意,內建的事件是射後不理的,若服務為離線狀態則事件將會丟失。對於需要持久、耐用及可靠的事件請使用 moleculer-channels

平衡事件

事件監聽器是按邏輯群組排列的,因此邏輯群組中僅有一個監聽器會被觸發。

假設你有三個服務 MAILPAYMENTBILLING ,每個服務都訂閱到 user.purchased ,並且啟動了一個 MAIL 服務、兩個 PAYMENT 服務及兩個 BILLING 服務。當你發出 user.purchased 事件時,將只有一個 MAIL 服務、一個 PAYMENT 服務及一個 BILLING 服務實例的事件會被觸發。


Fig. 1. 平衡事件範例

group 名稱預設會是服務名稱,但是它可以在服務的事件中設定覆蓋。

module.exports = {
    name: "payment",
    events: {
        "order.created": {
            // 以 "other" 註冊覆蓋預設的 "payment" 群組名稱
            group: "other",
            handler(ctx) {
                console.log("Payload:", ctx.params);
                console.log("Sender:", ctx.nodeID);
                console.log("Metadata:", ctx.meta);
                console.log("The called event name:", ctx.eventName);
            }
        }
    }
}

發送平衡事件

你可以使用 broker.emit 函數來發送平衡事件。

broker.emit(eventName[, payload[, groups]]);

參數說明:

  • eventName <String> 事件名稱
  • payload <Object> 資料參數
  • groups <String> | <String[]> 服務名稱

範例:

// 限 `mail` 與 `payments` 接收
broker.emit("user.created", { user }, ["mail", "payments"]);

廣播事件

使用 broadcast 可以發送廣播至所有的本地及遠端事件。但它不會進行事件平衡,所有的服務實例都會接收到事件。


Fig. 2. 廣播事件範例

發送廣播事件

使用 broker.broadcast 函數來發送廣播事件。

broker.broadcast(eventName[, payload[, groups]]);

參數說明:

  • eventName <String> 事件名稱
  • payload <Object> 資料參數
  • groups <String> | <String[]> 服務名稱

範例:

// 所有的 `user` 與 `purchase` 都接收
broker.broadcast("user.created", { user }, ["user", "purchase"]);

本地廣播事件

使用 broker.broadcastLocal 函數限制僅對本地服務發送廣播事件。

broker.broadcastLocal(eventName[, payload[, groups]]);

訂閱到事件

從 v0.14 版事件處理開始支援 Context。如果你使用事件驅動架構並想要追蹤事件,那麼事件 Context 會是很有幫助的。事件擁有與 Actions 非常相近的 Context,差別僅在於一些新事件相關屬性。完整清單請參閱:

https://moleculer.services/docs/0.14/context.html

範例:事件處理中的 context 以及發送事件

module.exports = {
    name: "accounts",
    events: {
        "user.created"(ctx) {
            console.log("Payload:", ctx.params);
            console.log("Sender:", ctx.nodeID);
            console.log("Metadata:", ctx.meta);
            console.log("The called event name:", ctx.eventName);

            ctx.emit("accounts.created", { user: ctx.params.user });
        },
        "user.removed": {
            // 強制使用新版 context
            context: true,
            handler(ctx) {
                console.log(`${this.broker.nodeID}:${this.fullName}: Event '${ctx.eventName}' received. Payload:`, ctx.params, ctx.meta);
            }
        },
        "user.oldCreated": {
            context: false,
            // 此為 v0.13 版參數格式,建議直接使用新版 v0.14 寫法
            handler(payload, sender, event, ctx) {
                console.log("Payload:", payload);
                console.log("Sender:", sender);
                console.log("Metadata:", ctx.meta);
                console.log("The called event name:", event);
            }
        }
    }
};

範例:使用萬用字元 (?, *, **) 訂閱事件。

module.exports = {
    name: "accounts",
    events: {
        // 訂閱至所有的 `user` 事件
        "user.*"(ctx) {
            console.log("User event:", ctx.params);
        },
        // 訂閱至所有的事件
        "**"(ctx) {
            console.log(`Event '${ctx.eventName}' received from ${ctx.nodeID} node:`, ctx.params);
        }
    }
};

事件參數驗證

事件也支援類似於 Actions 的參數驗證器。就如 Actions 的定義,你應該在事件中定義 params 並使用內建 Validator 來驗證參數。

module.exports = {
    name: "mailer",
    events: {
        "send.mail": {
            // 驗證參數
            params: {
                from: "string|optional",
                to: "email",
                subject: "string"
            },
            handler(ctx) {
                this.logger.info("Event received, parameters OK!", ctx.params);
            }
        }
    }
};

內建事件

服務中內建了一些廣播事件。這些事件會以字首為 $ 字號進行命名。

  • $services.changed 節點載入或銷毀
  • $circuit-breaker.opened 斷路器狀態變更為 open
  • $circuit-breaker.half-opened 斷路器狀態變更為 half-open
  • $circuit-breaker.closed 斷路器狀態變更為 closed
  • $node.connected 節點連線或重新連線
  • $node.updated 節點更新資訊時
  • $node.disconnected 節點斷線
  • $broker.started 服務啟動
  • $broker.stopped 服務停止
  • $transporter.connected Transporter 連線
  • $transporter.disconnected Transporter 斷線
  • $broker.error 服務錯誤
  • $transit.error Transit 錯誤
  • $transporter.error Transporter 錯誤
  • $cacher.error Cacher 錯誤
  • $discoverer.error 服務搜尋錯誤

由於內建事件繁多,詳情請參閱官方手冊:

https://moleculer.services/docs/0.14/events.html#Internal-events

參考文獻

[1] Events, https://moleculer.services/docs/0.14/events.html

家家酒小劇場

  • Otter - 訂閱事件中的 context 設定是用來做什麼的呢?
  • Boxy - context 是用來將舊版的參數格式強制改為新版,假如你不是由舊版升級上來的使用者,可以直接忽略 context 設定。

上一篇
Day 8 : Actions - Part 2
下一篇
Day 10 : Context
系列文
Moleculer 家家酒31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言